﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net.Sockets;
using System.Threading;
using MdcService.Structure;
using MdcService.Structure.Enum;
using Modbus.Device;

namespace MdcService.Machine
{
	public class MoxaMachine:BaseMachine
	{
		private TcpClient _tcpClient;
		private ModbusIpMaster _modbusIpMaster;
		private Dictionary<string, string> _innerBuffer = new Dictionary<string, string>();
		private ManualResetEvent _manualResetEvent = new ManualResetEvent(false);
		private int _tcpclienttimeout = 1000;
		public override MachineType Type { get;  set; } = MachineType.Moxa;

		public override void Connect()
		{
			if (!IsConnected)
			{
				try
				{
					_tcpClient = new TcpClient();
					_tcpClient.ReceiveTimeout = 500;
					_tcpClient.SendTimeout = 500;
					ConnectWithTimeout(_tcpclienttimeout);
					_modbusIpMaster = ModbusIpMaster.CreateIp(_tcpClient);
					LastConnected = DateTime.Now;
					Failures = 0;
				}
				catch (Exception)
				{
					Failures = Failures > 100 ? 99 : Failures + 1;
					throw;
				}
			}
		}

		public override void Disconnect()
		{
			if (IsConnected)
			{
				_modbusIpMaster.Dispose();
				_tcpClient.Close();
				IsConnected = false;
			}
		}

		public override void Read()
		{
			if (!IsConnected)
			{
				throw new Exception("disconnected!");
			}
			ushort[] dis;
			ushort[] ais;
			List<byte> bytes = new List<byte>();
			try
			{
				dis = _modbusIpMaster.ReadInputRegisters(48, 1);
				ais = _modbusIpMaster.ReadInputRegisters(520, 8);
			}
			catch (Exception e)
			{
				IsConnected = false;
				_tcpClient.Client.Close();
				throw;
			}
			if (dis?.Length == 1)
			{
				_innerBuffer["DI0"] = (1 & dis[0]).ToString();
				_innerBuffer["DI1"] = (1 & (dis[0] >> 1)).ToString();
				_innerBuffer["DI2"] = (1 & (dis[0] >> 2)).ToString();
				_innerBuffer["DI3"] = (1 & (dis[0] >> 3)).ToString();
				_innerBuffer["DIO0"] = (1 & (dis[0] >> 4)).ToString();
				_innerBuffer["DIO1"] = (1 & (dis[0] >> 5)).ToString();
				_innerBuffer["DIO2"] = (1 & (dis[0] >> 6)).ToString();
				_innerBuffer["DIO3"] = (1 & (dis[0] >> 7)).ToString();
			}
			if (ais?.Length == 8)
			{
				foreach (ushort v in ais)
				{
					bytes.Add(Convert.ToByte(v & byte.MaxValue));
					bytes.Add(Convert.ToByte((v >> 8) & byte.MaxValue));
				}
				var x = bytes.ToArray();

				_innerBuffer["AI0"] = BitConverter.ToSingle(x, 0).ToString(CultureInfo.InvariantCulture);
				_innerBuffer["AI1"] = BitConverter.ToSingle(x, 4).ToString(CultureInfo.InvariantCulture);
				_innerBuffer["AI2"] = BitConverter.ToSingle(x, 8).ToString(CultureInfo.InvariantCulture);
				_innerBuffer["AI3"] = BitConverter.ToSingle(x, 12).ToString(CultureInfo.InvariantCulture);
			}
			foreach (var key in Values)
			{
                RefreshItem(key.Value.Path,key.Value.Value);
			}
			LastRead = DateTime.Now;
		}

		public void ConnectWithTimeout(int timeout)
		{
			_manualResetEvent.Reset();
			_tcpClient.BeginConnect(Path, 502, ConnectCallback, _tcpClient);
			if (_manualResetEvent.WaitOne(3000, false))
			{
				IsConnected = true;
			}
			else
			{
				_tcpClient.Close();
				IsConnected = false;
				throw new TimeoutException();
			}
		}
		public void ConnectCallback(IAsyncResult iAsyncResult)
		{
			try
			{
				TcpClient _tcpClient = iAsyncResult as TcpClient;
				_tcpClient?.EndConnect(iAsyncResult);
			}
			catch (Exception e)
			{
				throw;
			}
			finally
			{
				_manualResetEvent.Set();
			}
		}

		public override void Dispose()
		{
			_modbusIpMaster.Dispose();
			_tcpClient.Close();
		}
	}
}
